package com.tron.controller.order;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tron.context.QuartzContext;
import com.tron.context.RedisContext;
import com.tron.controller.order.req.PayOrderAddReq;
import com.tron.controller.order.resp.PayOrderResp;
import com.tron.convertor.OrderConvertor;
import com.tron.dto.R;
import com.tron.dto.ResultCode;
import com.tron.entity.PayOrder;
import com.tron.entity.TronAccount;
import com.tron.service.PayOrderService;
import com.tron.service.TronAccountService;
import com.tron.utils.QuartzUtils;
import com.tron.utils.tron.TronAddress;
import com.tron.utils.tron.TronUtils;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 订单控制器
 */
@RestController
@RequestMapping("/order")
@Api(value = "订单控制器",tags = "订单控制器")
@Slf4j
public class PayOrderController {

    @Autowired
    private TronUtils tronUtils;

    @Autowired
    private RedisContext redisContext;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private Scheduler scheduler; //Quartz定时任务调度

    @Autowired
    private PayOrderService payOrderService;

    @Autowired
    private TronAccountService tronAccountService; //Tron-账户Service



    @GetMapping("/netty")
    @ApiOperation(value = "创建订单(Netty)",notes = "创建订单(amount单位是TRX/个)")
    public R<?> createOrderNetty(@RequestParam("amount") Integer amount,@RequestParam("address") String address){
        TronAccount tronAccount = null;
        //先看看缓存中有没有可以复用的账户
        ScanOptions options = ScanOptions.scanOptions().match("account:reuse:*").count(1).build();
        RedisSerializer<String> keySerializer = redisTemplate.getKeySerializer();
         Cursor cursor = (Cursor) redisTemplate.executeWithStickyConnection(redisConnection -> new ConvertingCursor<>(redisConnection.scan(options), keySerializer::deserialize));
         String key = null;
         Object reuseAccount; //可复用的账户key
         while(cursor.hasNext()){
           key=cursor.next().toString();
         }

        //取出并删除
        reuseAccount = (key!=null) ? redisTemplate.opsForValue().get(key):null;
        tronAccount =  (reuseAccount!=null) ? (TronAccount) reuseAccount:null;
        if(Objects.isNull(reuseAccount)){
            tronAccount = tronUtils.generateAddress(); //创建
            //tronAddress = new TronAddress(address,"2222222222222",new Date(),new BigDecimal(0));
            //先存起来 订单完成之后销毁
            String accountReuseKey = redisContext.getAccountReuse(tronAccount.getAddress());
            redisTemplate.opsForValue().set(accountReuseKey, tronAccount);
        }

        Map<String,String> map=new HashMap<>();
        map.put("message","创建成功");
        map.put("address",tronAccount.getAddress());
        PayOrder payOrder = new PayOrder();
        payOrder.setCreateTime(new Date());
        payOrder.setStatus(0);
        //order.setAmount(amount);
        payOrder.setAddress(tronAccount.getAddress());
        payOrder.setPrivateKey(tronAccount.getPrivateKey());

        //设置订单在redis的存活时间
        String orderPaykey = redisContext.getOrderPayKey(tronAccount.getAddress());
        redisTemplate.opsForValue().set(orderPaykey, payOrder,60*10, TimeUnit.SECONDS);

        //设置记录 永不过期
        String recordKey = redisContext.getRecordKey(tronAccount.getAddress());
        redisTemplate.opsForValue().set(recordKey, payOrder);

        //模拟连接socket
        //模拟发送
//        try {
//            //QuartzBean
//            QuartzContext quartzContext = new QuartzContext();
//            quartzContext.setJobName("job_"+tronAddress.getAddress());
//            quartzContext.setCronExpression("*/10 * * * * ?");
//            quartzContext.setJobClass("com.tron.task.tron.OrderListener");
//
//            Map<String,Object> argument = new HashMap<>();
//            argument.put("key",tronAddress.getAddress());
//            quartzContext.setData(argument);
//            QuartzUtils.createScheduleJob(scheduler, quartzContext);
//        } catch (Exception e) {
//           log.error("监听事件触发失败");
//        }
//        log.info("订单创建成功");
        return R.ok(map);
    }

    @PostMapping("/create")
    @ApiOperation(value = "创建订单(Quartz)",notes = "创建订单(amount单位是TRX/个)")
    public R<?> createOrderQuartz(@RequestBody PayOrderAddReq payOrderAddReq){
        TronAccount newTronAccount= new TronAccount(payOrderAddReq.getAddressTest(),"11111111111112222222",0L,0,1);

        //获取账户 普通账户或者是可复用的账户
        TronAccount tronAccount = this.getMultiplexAccount(newTronAccount);

        if(Objects.isNull(tronAccount)){
            return R.error(ResultCode.ORDER_ERROR_REPEAT);
        }

        //对象转换
        PayOrder payOrder = OrderConvertor.MAPPER.ob2en(payOrderAddReq);
        payOrder.setStatus(0); //设置状态为订单未完成
        payOrder.setCreateTime(new Date()); //设置当前时间
        payOrder.setAddress(tronAccount.getAddress()); //设置地址
        payOrder.setPrivateKey(tronAccount.getPrivateKey()); //设置私钥

        //记录订单信息
        payOrderService.save(payOrder);

        //转换返回对象
        PayOrderResp payOrderResp = OrderConvertor.MAPPER.en2resp(payOrder);
        payOrderResp.setOrderId(payOrder.getId());

        //执行订单后置处理器
        orderPostProcessor(payOrder);

        //创建定时任务
        createTask(payOrder);
        return R.ok(payOrderResp);
    }


    /**
     * 获取可复用的账户 - 从Redis取对象 以及保存
     * 没有账户会自动创建账户 并 保存
     * @return TronAddress 账户对象
     */
    public TronAccount getMultiplexAccount(TronAccount test){
        TronAccount tronAccount=null;

        TronAccount oneEntity = tronAccountService.getOne(new LambdaQueryWrapper<TronAccount>()
                .eq(TronAccount::getIsOrderFlow, 0) // 没有走流程
                .eq(TronAccount::getIsReuse,1) // 可复用的账户
                .last("limit 1")
        );

        if(Objects.nonNull(oneEntity)) {
            //更新数据库 因为目前要走订单流程 更新流程状态
            oneEntity.setIsOrderFlow(1);
            boolean b = tronAccountService.updateById(oneEntity);
            //oneEntity.setBalance(0L);
            return oneEntity;
        }

        //没有的话就创建
        //tronAccount = tronUtils.generateAddress(); //创建
        tronAccount = test;

        //查询是否含有重复
        long count = tronAccountService.count(new LambdaQueryWrapper<TronAccount>().eq(TronAccount::getAddress, tronAccount.getAddress()));

        if(count == 0){
            //记录账户信息
            tronAccountService.save(tronAccount);
        }else{
            log.error("数据库账户有重复--->"+tronAccount.getAddress());
            tronAccount=null;
        }
        return tronAccount;
    }

    /**
     * 订单后置处理器
     * 当订单存库完成后处理的事件
     */
    public void orderPostProcessor(PayOrder payOrder){
        //设置订单在redis的存活时间
        String orderPaykey = redisContext.getOrderPayKey(payOrder.getAddress());
        redisTemplate.opsForValue().set(orderPaykey, payOrder,60*10, TimeUnit.SECONDS);
    }

    /**
     * 创建定时任务
     */
    public void createTask(PayOrder payOrder){
        try {
            QuartzContext quartzContext = new QuartzContext();
            quartzContext.setJobName("order_"+ payOrder.getAddress());
            quartzContext.setJobClass("com.tron.task.tron.OrderListener");
            quartzContext.setCronExpression("*/10 * * * * ?");

            Map<String,Object> mapData = new HashMap<>();
            mapData.put("address", payOrder.getAddress());
            mapData.put("privateKey", payOrder.getPrivateKey());
            mapData.put("jobName","order_"+ payOrder.getAddress());
            quartzContext.setData(mapData);
            QuartzUtils.createScheduleJob(scheduler, quartzContext);
        } catch (Exception e) {
            log.error("任务创建失败!!");
        }
    }

}
